package com.example.kekewaimaibao.shop.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.kekewaimaibao.address.constant.AddressConstant;
import com.example.kekewaimaibao.core.constant.RestConstant;
import com.example.kekewaimaibao.core.utils.RegexUtil;
import com.example.kekewaimaibao.goods.model.GoodsDO;
import com.example.kekewaimaibao.goods.service.IGoodsService;
import com.example.kekewaimaibao.order.model.OrderDO;
import com.example.kekewaimaibao.order.service.IOrderService;
import com.example.kekewaimaibao.shop.model.ShopDO;
import com.example.kekewaimaibao.shop.service.IShopService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @author: xuxiang
 * @date: 2022/3/6 22:52 星期日
 * @description:
 * @version: 1.0
 */
@Slf4j
@RestController
@RequestMapping(ShopController.PATH)
@Api(tags = "商家信息控制层")
@CrossOrigin
public class ShopController {

    public static final String PATH = RestConstant.VERSION_V1 + "/shop";

    @Autowired
    IShopService shopService;

    @Autowired
    IGoodsService goodsService;

    @Autowired
    IOrderService orderService;

    /**
     * 建议弃用全表查询
     * @return R
     */
    @ApiOperation(value = "所有商家列表")
    @GetMapping("/list")
    public R list() {
        List<ShopDO> list = shopService.list(null);
        return R.ok(list);
    }

    /**
     * 可通过商家名称进行模糊分页
     * @param current 当前页
     * @param limit 每页数据个数
     * @param shopDO 商家信息
     * @return R
     */
    @ApiOperation(value = "分页查询商家信息")
    @PostMapping("/page/{current}/{limit}")
    public R page(@PathVariable long current, @PathVariable long limit,
                  @RequestBody(required = false) ShopDO shopDO) {
        Page<ShopDO> page = new Page<>(current, limit);
        QueryWrapper<ShopDO> wrapper = null;
        if (ObjectUtil.isNotNull(shopDO)) {
            wrapper = new QueryWrapper<>();
            // 根据商家名称模糊分页
            if (StrUtil.isNotBlank(shopDO.getShopName())) {
                wrapper.like("shop_name", shopDO.getShopName());
            }
        }
        shopService.page(page, wrapper);
        long total = page.getTotal();
        List<ShopDO> records = page.getRecords();
        Map map = new HashMap<>(4);
        map.put("current", current);
        map.put("limit", limit);
        map.put("total", total);
        map.put("records", records);
        return R.ok(map);
    }

    @ApiOperation(value = "添加商家信息")
    @PostMapping("/save")
    public R save(@RequestBody ShopDO shopDO) {
        boolean flag = shopService.save(shopDO);
        if (flag) {
            return R.ok("后台添加商家信息成功");
        } else {
            return R.failed("后台添加商家信息失败");
        }
    }

    @ApiOperation(value = "删除商家信息")
    @PostMapping("/remove/{id}")
    public R remove(@PathVariable Long id) {
        boolean flag = shopService.removeById(id);
        if (flag) {
            return R.ok("后台删除id为" + id +"的商家信息成功");
        } else {
            return R.failed("后台删除商家信息失败");
        }
    }

    @ApiOperation(value = "更新商家信息")
    @PostMapping("update")
    public R update(@RequestBody ShopDO shopDO) throws Exception {
        UpdateWrapper<ShopDO> wrapper = new UpdateWrapper<>();
        if (ObjectUtil.isNotNull(shopDO)) {
            if (StrUtil.isBlank(shopDO.getProvince()) || StrUtil.isBlank(shopDO.getCity()) ||
                StrUtil.isBlank(shopDO.getDistrict()) || StrUtil.isBlank(shopDO.getAddressDetail())) {
                return R.failed("商家地址信息不完整");
            } else {
                String addressInfo = shopDO.getProvince() + shopDO.getCity()
                        + shopDO.getDistrict() + shopDO.getAddressDetail();
                String location = getLocation(addressInfo);
                String[] strings = location.split(",");
                String longitude = strings[0];
                String latitude = strings[1];
                shopDO.setLongitude(longitude);
                shopDO.setLatitude(latitude);
            }
        }

        boolean flag = shopService.updateById(shopDO);
        if (flag) {
            return R.ok("后台更新id为" + shopDO.getShopId() + "的商家信息成功");
        } else {
            return R.failed("后台更新商家信息失败");
        }
    }

    @ApiOperation(value = "批量删除商家信息")
    @PostMapping("/remove-ids/{ids}")
    public R deleteBatchIds(@PathVariable("ids")String[] ids) {
        List<String> list = Arrays.asList(ids);
        boolean flag = shopService.removeByIds(list);
        if (flag) {
            return R.ok("批量删除商家信息成功");
        } else {
            return R.failed("批量删除商家信息失败");
        }
    }

    @ApiOperation(value = "通过id查找商家信息")
    @GetMapping("/get-by-id/{id}")
    public R getByShopId(@PathVariable Long id) {
        ShopDO shopDO = shopService.getById(id);
        if (ObjectUtil.isNotNull(shopDO)) {
            return R.ok(shopDO);
        } else {
            return R.failed("未找到id为" + id + "的商家");
        }
    }

    /**
     * 商家注册需要很多信息（包括商家的名称、电话、邮箱、密码、标签、省、市、区、详细地址）
     * @param shopDO 商家信息
     * @return R
     * @throws Exception
     */
    @ApiOperation(value = "商家注册")
    @PostMapping("/register")
    public R register(@RequestBody ShopDO shopDO) throws Exception {
        Map<String, Object> map = JSON.parseObject(JSON.toJSONString(shopDO), Map.class);
        // TODO:判断表单字段不能为空
        if (!StrUtil.isAllNotBlank((String) map.get("shopName"), (String) map.get("phone"),
                (String) map.get("email"), (String) map.get("password"), (String) map.get("shopTag"),
                (String) map.get("province"), (String) map.get("city"), (String) map.get("district"),
                (String) map.get("addressDetail"))) {
            return R.failed("商家某字段为空");
        }
        // 判断表单字段是否合法
        // 昵称格式：限16个字符，支持中英文、数字、减号或下划线
        if (!RegexUtil.isNickName((String) map.get("shopName"))) {
            return R.failed("商家名称格式有误");
        }
        if (!RegexUtil.isPhone((String) map.get("phone"))) {
            return R.failed("商家电话格式有误");
        }
        if (!RegexUtil.isEmail((String) map.get("email"))) {
            return R.failed("商家邮箱格式有误");
        }
        if (!RegexUtil.isPassword((String) map.get("password"))) {
            return R.failed("商家密码格式有误");
        }
        if (!("1".equals(map.get("shopTag")) || "2".equals(map.get("shopTag"))
            || "3".equals(map.get("shopTag")) || "4".equals(map.get("shopTag")))){
            return R.failed("商家标签格式有误");
        }

        // 获取商家经纬度信息（高德经纬度）
        StringBuffer sb = new StringBuffer();
        sb.append(shopDO.getProvince()).append(shopDO.getCity())
                .append(shopDO.getDistrict()).append(shopDO.getAddressDetail());
        String addressInfo = sb.toString();
        String location = getLocation(addressInfo);
        String[] strings = location.split(",");
        String longitude = strings[0];
        String latitude = strings[1];
        shopDO.setLongitude(longitude);
        shopDO.setLatitude(latitude);

        boolean flag = shopService.save(shopDO);
        if (flag) {
            return R.ok("商家注册成功");
        } else {
            return R.failed("商家注册失败");
        }
    }

    /**
     * 商家登录的功能，需要填写手机号和密码
     * @param shopDO
     * @return R
     */
    @ApiOperation(value = "商家登录")
    @PostMapping("/login")
    public R login(@RequestBody ShopDO shopDO) {
        String phone = shopDO.getPhone();
        String password = shopDO.getPassword();
        if (!RegexUtil.isPhone(phone)) {
            log.info("手机号格式有误 ---> {}", phone);
            return R.failed("手机号格式有误 ---> " + phone);
        }
        if (!RegexUtil.isPassword(password)) {
            log.info("密码格式有误 ---> {}", password);
            return R.failed("密码格式有误(限16个字符，支持英文、数字、减号或下划线) ---> " + password);
        }

        QueryWrapper<ShopDO> wrapper = new QueryWrapper<>();
        wrapper.eq("phone", phone);
        shopDO = shopService.getOne(wrapper);
        if (ObjectUtil.isNull(shopDO)) {
            return R.failed("手机号输入错误");
        }
        if (!password.equals(shopDO.getPassword())) {
            return R.failed("密码输入错误");
        } else {
            Map<String, Object> map = JSON.parseObject(JSON.toJSONString(shopDO), Map.class);
            R result = new R();
            result.setMsg("登录成功");
            result.setData(map);
            return result;
        }
    }

    /**
     * 商家通过手机号和邮箱重置密码
     * @param shopDO
     * @return R
     */
    @ApiOperation(value = "商家忘记密码")
    @PostMapping("/reset")
    public R resetPassword(@RequestBody ShopDO shopDO) {
        String phone = shopDO.getPhone();
        String email = shopDO.getEmail();
        String password = shopDO.getPassword();

        if (!RegexUtil.isPhone(phone)) {
            log.info("手机号格式有误 ---> {}", phone);
            R result = R.failed("手机号格式有误 ---> " + phone);
            result.setCode(520);
            return result;
        }
        if (!RegexUtil.isEmail(email)) {
            log.info("邮箱格式有误 ---> {}", email);
            R result = R.failed("邮箱格式有误 ---> " + email);
            result.setCode(520);
            return result;
        }
        if (!RegexUtil.isPassword(password)) {
            log.info("密码格式有误 ---> {}", password);
            R result = R.failed("密码格式有误(限16个字符，支持英文、数字、减号或下划线) ---> " + password);
            result.setCode(520);
            return result;
        }

        UpdateWrapper<ShopDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("phone", phone);
        wrapper.eq("email", email);
        wrapper.set("password", password);
        boolean flag = shopService.update(wrapper);
        if (flag) {
            R result = new R();
            result.setMsg("密码重置成功");
            result.setCode(200);
            return result;
        } else {
            R result = R.failed("密码重置失败");
            result.setCode(520);
            return result;
        }
    }

    /**
     * 商家登录之后修改密码，需要提供手机号的信息（注意后端并没有对商家密码进行原密码是否相等的校验）
     * @param shopDO
     * @return R
     */
    @ApiOperation(value = "商家修改密码")
    @PostMapping("/change-password")
    public R changePassword(@RequestBody ShopDO shopDO) {
//        log.info("password ---> {}", shopDO.getPassword());
        if (!RegexUtil.isPassword(shopDO.getPassword())) {
            R result = new R();
            result.setCode(520);
            return R.failed("密码格式错误");
        }
        UpdateWrapper<ShopDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("phone", shopDO.getPhone());
        wrapper.set("password", shopDO.getPassword());
        boolean flag = shopService.update(wrapper);
        if (flag) {
            R result = new R();
            result.setMsg("修改密码成功");
            result.setCode(200);
            return result;
        } else {
            R result = R.failed("修改密码失败");
            result.setCode(520);
            return result;
        }
    }

    /**
     * 因为商家地址是唯一的，我们直接放到了商家持久层对象中
     * @param shopDO
     * @return R
     * @throws Exception
     */
    @ApiOperation(value = "商家修改地址")
    @PostMapping("/change-address")
    public R changeAddress(@RequestBody ShopDO shopDO) throws Exception {
        if (StrUtil.isBlank(shopDO.getProvince()) || StrUtil.isBlank(shopDO.getCity())
                || StrUtil.isBlank(shopDO.getDistrict()) || StrUtil.isBlank(shopDO.getAddressDetail())) {
            return R.failed("省/市/区/详细地址未填写");
        }
        if (StrUtil.isBlank(shopDO.getPhone())) {
            return R.failed("数据库错误：商家信息不完整");
        }

        // 封装经纬度信息
        StringBuffer sb = new StringBuffer();
        sb.append(shopDO.getProvince()).append(shopDO.getCity())
                .append(shopDO.getDistrict()).append(shopDO.getAddressDetail());
        String addressInfo = sb.toString();
        String location = getLocation(addressInfo);
        String[] strings = location.split(",");
        String longitude = strings[0];
        String latitude = strings[1];
        shopDO.setLongitude(longitude);
        shopDO.setLatitude(latitude);

        UpdateWrapper<ShopDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("phone", shopDO.getPhone());
        wrapper.set("province", shopDO.getProvince());
        wrapper.set("city", shopDO.getCity());
        wrapper.set("district", shopDO.getDistrict());
        wrapper.set("longitude", shopDO.getLongitude());
        wrapper.set("latitude", shopDO.getLatitude());
        boolean flag = shopService.update(wrapper);

        if (flag) {
            R result = new R();
            result.setMsg("修改地址成功");
            result.setCode(200);
            return result;
        } else {
            R result = R.failed("修改地址失败");
            result.setCode(520);
            return result;
        }
    }

    /**
     * 用户前端模糊查询查询商家列表使用，注意一下路径命名（最好变成list-shop-name）
     * @param shopName 商家名称
     * @return R
     */
    @ApiOperation(value = "通过商家名称查询")
    @GetMapping("/get-by-name/{shopName}")
    public R getByShopName(@PathVariable String shopName) {
        QueryWrapper<ShopDO> wrapper = new QueryWrapper<>();
        wrapper.like("shop_name", shopName);
        List<ShopDO> list = shopService.list(wrapper);
//        List<Long> ids = new ArrayList<>();
//        for (ShopDO shopDO : list) {
//            ids.add(shopDO.getShopId());
//        }
        return R.ok(list);
    }

    /**
     * 商家前端模糊获取商品列表
     * @param goodsDO 商品信息
     * @return R
     */
    @ApiOperation(value = "通过商家id和商品名称，模糊查询商家的商品列表")
    @PostMapping("/list-blurry")
    public R GoodsListByBlurry(@RequestBody GoodsDO goodsDO) {
        Long shopId = goodsDO.getShopId();
        String nameLike = goodsDO.getName();
        if (ObjectUtil.isNull(shopId)) {
            return R.failed("商家id为空");
        }
        QueryWrapper<GoodsDO> wrapper = new QueryWrapper<>();
        wrapper.eq("shop_id", shopId);
        List<GoodsDO> list = new ArrayList<>();
        if (StrUtil.isBlank(nameLike)) {
            list = goodsService.list(wrapper);
        } else {
            wrapper.like("name", nameLike);
            list = goodsService.list(wrapper);
        }
        R result = new R();
        result.setData(list);
        result.setCode(200);
        return result;
    }

    /**
     * 通过shopId获取商家数据看板
     * 数据包括：订单总数，客户总数，销售总额，商品总数
     * @param shopId 商家ID
     * @return R
     */
    @ApiOperation(value = "商家端数据看板")
    @GetMapping("/dashboard/{shopId}")
    public R getDashboardData(@PathVariable Long shopId) {
        QueryWrapper<OrderDO> orderWrapper = null;
        QueryWrapper<GoodsDO> goodsWrapper = null;
        Map<String, Object> map = null;
        Map<String, Object> resultMap = null;

        // 统计订单总数
        orderWrapper = new QueryWrapper<>();
        orderWrapper.eq("shop_id", shopId);
        int orderCount = orderService.count(orderWrapper);

        // 统计客户总数
        orderWrapper = new QueryWrapper<>();
        orderWrapper.eq("shop_id", shopId);
        orderWrapper.select("count(distinct `user_id`) as user_count");
        map = orderService.getMap(orderWrapper);
        int userCount = Integer.valueOf(map.get("user_count").toString());

        // 统计销售总额
        orderWrapper = new QueryWrapper<>();
        orderWrapper.eq("shop_id", shopId);
        orderWrapper.select("sum(`box_cost`) as sale_money");
        map = orderService.getMap(orderWrapper);
        double saleMoney = Double.valueOf(map.get("sale_money").toString());

        // 统计商品总数
        goodsWrapper = new QueryWrapper<>();
        goodsWrapper.eq("shop_id", shopId);
        int goodsCount = goodsService.count(goodsWrapper);

        resultMap = new HashMap<>();
        resultMap.put("orderCount", orderCount);
        resultMap.put("userCount", userCount);
        resultMap.put("saleMoney", saleMoney);
        resultMap.put("goodsCount", goodsCount);

        R result = new R();
        result.setCode(200);
        result.setData(resultMap);
        return result;
    }

    /**
     * 调用高德开放平台API（每日有限额）进行的定位，获取经纬信息
     * @param addressInfo 地址详细信息（已进行省、市、区、详细地址拼接的信息）
     * @return "经度,纬度"（保留小数点后六位）
     * @throws Exception
     */
    private String getLocation(String addressInfo) throws Exception {
        String url = AddressConstant.GEO_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(2);
        map.put("key", key);
        map.put("address", addressInfo);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        String location = jsonObject.getJSONArray("geocodes").getJSONObject(0).getString("location");
        return location;
    }
}
